﻿using Newtonsoft.Json;
using Simple.Framework.Protocol;
using Simple.SnowFlake;
using Simple.Tools;
using SimpleNet.Handle;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

/*********************************************************
 * 命名空间 Simple.Framework.Protocol
 * 接口名称 MDTDataPackProtocol
 * 开发人员：zdm
 * 创建时间：2023/11/23 9:23:16
 * 描述说明：
 * 更改历史：
 * 
 * *******************************************************/
namespace SimpleNet.Protocol
{
	public class MDTDataPackProtocol: IMDTDataPackProtocol
	{
		public MDTDataPackProtocol() 
		{
			Head = new byte[2] { 0xA8, 0x30 };
			Tail = new byte[2] { 0x3E, 0x24 };
		}

		/// <summary>
		/// 
		/// </summary>
		public readonly byte[] Head;
		/// <summary>
		/// 
		/// </summary>

		public readonly byte[] Tail;

		/// <summary>
		/// 初始化一个包
		/// </summary>
		/// <param name="len"></param>
		/// <param name="commandId"></param>
		/// <param name="packStatus"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentException"></exception>
		public  byte[] InitializeDataPack(int len, int commandId, ePackStatus packStatus)
		{
			if (len < 7)
			{
				throw new ArgumentException("长度必须大7!");
			}
			byte[] buffer = new byte[len];
			Array.Copy(Head, 0, buffer, 0, 2);
			buffer[2] = (byte)commandId;
			buffer[3] = (byte)((int)packStatus & 0xFF);
			return buffer;
		}
		#region reply
		/// <summary>
		/// login
		/// </summary>
		/// <param name="commandId"></param>
		/// <param name="ReceivePackType"></param>
		/// <param name="IpAddress"></param>
		/// <param name="Port"></param>
		/// <param name="updateflag"></param>
		/// <returns></returns>
		public  byte[] LoginReply(int commandId, ePackStatus ReceivePackType, string IpAddress, int Port, int updateflag = 0)
		{
			//2+1+1=4+1

			byte[] buffer = InitializeDataPack(34, commandId, ReceivePackType);//new byte[34];
			buffer[4] = (byte)(updateflag & 0xFF);
			Array.Copy(IpAddress.IPToBytes(), 0, buffer, 5, 4);
			Array.Copy(Port.IntToBytes(), 2, buffer, 9, 2);
			Array.Copy(DateTime.Now.CurrentTimeToBytes(), 0, buffer, 11, 6);
			///
			Array.Copy(DateTime.Now.CurrentDateToBytes(), 0, buffer, 17, 6);
			//token暂不设置 8byte
			//获取校验和
			CompletePackCRC(buffer);
			return buffer;
		}
		/// <summary>
		/// heart
		/// </summary>
		/// <param name="CommandStatus"></param>
		/// <param name="commandId"></param>
		/// <returns></returns>
		public  byte[] HeartReply(int commandId, ePackStatus ReceivePackType)
		{
			byte[] buffer = InitializeDataPack(7, commandId, ReceivePackType);//new byte[7];
			CompletePackCRC(buffer);
			return buffer;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandId"></param>
		/// <param name="ReceivePackType"></param>
		/// <param name="json"></param>
		/// <returns></returns>
		public  byte[] ReceiveDeviceInfoReply(int commandId, ePackStatus ReceivePackType, string json)
		{
			byte[] dataBuffer = Encoding.UTF8.GetBytes(json);
			byte[] dataLength = BitConverter.GetBytes(dataBuffer.Length);
			Array.Reverse(dataLength);
			byte[] buffer = InitializeDataPack(dataBuffer.Length + 9, commandId, ReceivePackType);// new byte[dataBuffer.Length + 9];
			Array.Copy(dataLength, 2, buffer, 4, 2);
			Array.Copy(dataBuffer, 0, buffer, 6, dataBuffer.Length);
			CompletePackCRC(buffer);
			return buffer;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandId"></param>
		/// <param name="ReceivePackType"></param>
		/// <param name="totalSize"></param>
		/// <param name="totalPackNum"></param>
		/// <param name="firmwareVersion"></param>
		/// <returns></returns>
		public  byte[] VersionUpgradeReply(int commandId, ePackStatus ReceivePackType, int totalSize, int totalPackNum, string firmwareVersion)
		{
			byte[] buffer = InitializeDataPack(21, commandId, ReceivePackType);//new byte[21];

			Array.Copy(totalSize.numToByte(4), 0, buffer, 4, 4);
			Array.Copy(totalPackNum.numToByte(2), 0, buffer, 8, 2);

			var versionByte = Encoding.UTF8.GetBytes(firmwareVersion == null ? "" : firmwareVersion);
			Array.Copy(versionByte, 0, buffer, 10, 8);
			//获取校验和
			CompletePackCRC(buffer);
			return buffer;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandId"></param>
		/// <param name="ReceivePackType"></param>
		/// <param name="firmwareVersion"></param>
		/// <param name="totalPackNum"></param>
		/// <param name="currentPackNum"></param>
		/// <param name="currentPackDataLength"></param>
		/// <param name="currentPackData"></param>
		/// <returns></returns>
		public  byte[] VersionUpgradeDataReply(int commandId, ePackStatus ReceivePackType, string firmwareVersion, int totalPackNum, int currentPackNum, int currentPackDataLength, byte[] currentPackData)
		{
			byte[] buffer = InitializeDataPack(23 + currentPackDataLength, commandId, ReceivePackType); //new byte[23 + currentPackDataLength];
			var versionByte = Encoding.UTF8.GetBytes(firmwareVersion);
			Array.Copy(versionByte, 0, buffer, 4, 8);
			Array.Copy(totalPackNum.numToByte(2), 0, buffer, 12, 2);
			Array.Copy(currentPackNum.numToByte(2), 0, buffer, 14, 2);
			Array.Copy(currentPackDataLength.numToByte(4), 0, buffer, 16, 4);
			Array.Copy(currentPackData, 0, buffer, 20, currentPackDataLength);
			//获取校验和
			CompletePackCRC(buffer);
			return buffer;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandId"></param>
		/// <param name="ReceivePackType"></param>
		/// <returns></returns>
		public  byte[] ErrorReply(int commandId, ePackStatus ReceivePackType)
		{
			byte[] buffer = InitializeDataPack(7, commandId, ReceivePackType);// new byte[7];
			CompletePackCRC(buffer);
			return buffer;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="ReceivePackType"></param>
		/// <returns></returns>
		public  byte[] ErrorReply(ePackStatus ReceivePackType)
		{
			byte[] buffer = InitializeDataPack(7, 0, ReceivePackType);// new byte[7];
			CompletePackCRC(buffer);
			return buffer;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		//public  void SetDeviceInfo(IDTContext context)
		//{

		//	byte[] versionBuf = new byte[1];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 2, versionBuf, 0, 1);


		//	byte[] manufactureBuf = new byte[2];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 4, manufactureBuf, 0, 2);
		//	context.Device.Manufacture = Encoding.UTF8.GetString(manufactureBuf);

		//	byte[] idBuf = new byte[16];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 6, idBuf, 0, 16);
		//	context.Device.SN = Encoding.UTF8.GetString(idBuf);


		//	byte[] parentDeviceIDBuf = new byte[16];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 22, parentDeviceIDBuf, 0, 16);
		//	context.Device.ParentDeviceID = Encoding.UTF8.GetString(parentDeviceIDBuf);

		//	byte[] wareVersionBuf = new byte[8];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 38, wareVersionBuf, 0, 8);
		//	context.Device.WareVersion = Encoding.UTF8.GetString(wareVersionBuf);

		//	byte[] productTypeBuf = new byte[4];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 46, productTypeBuf, 0, 4);
		//	context.Device.ProductType = BitConverter.ToString(productTypeBuf).Replace("-", "");

		//	var ptype = int.Parse(context.Device.ProductType);

		//	context.Device.eProductType = (eProductType)ptype;


		//	byte[] authorizeKeyBuf = new byte[32];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 50, authorizeKeyBuf, 0, 32);
		//	context.Device.AuthorizeKey = Encoding.UTF8.GetString(authorizeKeyBuf);


		//	byte[] environmentBuf = new byte[1];
		//	Array.Copy(context.CurrentPack.ReceiveBuffer, 82, environmentBuf, 0, 1);
		//	context.Device.Environment = Encoding.UTF8.GetString(environmentBuf);
		//}
		public  bool CheckHeadAndTail(IContext context)
		{
			if (CheckHead(context) && CheckTail(context))
			{
				return true;
			}
			return false;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public  bool CheckHead(IContext context)
		{
			if (context.CurrentPack.HeaderBuffer[0] == Head[0] && context.CurrentPack.HeaderBuffer[1] == Head[1])
			{
				return true;
			}
			return false;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public  bool CheckTail(IContext context)
		{
			if (context.CurrentPack.TailBuffer[0] == Tail[0] && context.CurrentPack.TailBuffer[1] == Tail[1])
			{
				return true;
			}
			return false;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public  bool CalculateChecksum(IContext context)
		{
			int checksum = 0;
			foreach (byte chData in context.CurrentPack.CheckBuffer)
			{
				checksum += chData;
			}
			checksum &= 0xff;
			return checksum == context.CurrentPack.CRC;

		}
		#endregion
		/// <summary>
		/// 
		/// </summary>
		/// <param name="buffer"></param>
		/// <exception cref="ArgumentException"></exception>
		public  void CompletePackCRC(byte[] buffer)
		{
			if (buffer == null)
			{
				throw new ArgumentException("buffer 不能为空!");
			}
			buffer[buffer.Length-3] = (byte)buffer.CalculateChecksum(buffer.Length - 3);
			Array.Copy(Tail,0,buffer, buffer.Length-2,2);
		}


		public TProtocol GetProtocol<TProtocol>() where TProtocol : MDTDataPackProtocol
		{
			return (TProtocol)this;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="data"></param>
		/// <param name="commandId"></param>
		/// <returns></returns>
		public byte[] GetServerToClientData<TData>(TData data, ref long commandId)
		{
			byte[] dataBuffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
			byte[] dataLength = BitConverter.GetBytes(dataBuffer.Length);
			commandId = Worker.Builder().NextId();
			byte[] DownloadDataID = BitConverter.GetBytes(commandId);

			Array.Reverse(dataLength);

			
			byte[] buffer = new byte[dataBuffer.Length + 42];
			Array.Copy(Head, 0, buffer, 0, 2);
			buffer[2] = 0x12;
			Array.Copy(dataLength, 0, buffer, 3, 4);
			Array.Copy(dataBuffer, 0, buffer, 7, dataBuffer.Length);
			Array.Copy(DownloadDataID, 0, buffer,7+dataBuffer.Length, DownloadDataID.Length);
			buffer[buffer.Length-3]=(byte)buffer.CalculateChecksum(buffer.Length-3);
			Array.Copy(Tail,0,buffer,buffer.Length - 2, 2);
			return buffer;
		}

	}
}
